var Game = (function () {
  function Game(id) {
    //配置
    this.conf = {
      up: 1,
      right: 2,
      down: 3,
      left: 4,
    };
    //每次刷新豆豆数量
    this.pNum;
    //计时器更新速率
    this.US = 100;
    //单位格数量
    this.docNum = 2400;
    //单元格宽度
    this.docWidth = 20;
    //计时器id
    this.tickerId;
    //单位格列表
    this.docs = {};
    //容器id
    this.cId = id;
    //容器
    this.container;
    /* 游戏中相关*/
    this.state;
    this.snake = [];
    this.head;
    this.point;
    this.dir; //上右下左 1234
    this.tail;
    /*回调列表*/
    this.callList;
  }

  var c = Game,
    p = c.prototype;

  p.Main = function () {
    var self = this;
    self.container = document.getElementById(self.cId);
    self.callList = {};
    self.initController();
    self.initDoc();
  };

  p.initController = function () {
    var self = this;
    document.addEventListener(
      "keydown",
      function (ev) {
        var code = ev.code;
        switch (code) {
          case "ArrowUp":
            if (self.dir == self.conf.down) break;
            self.dir = self.conf.up;
            break;
          case "ArrowRight":
            if (self.dir == self.conf.left) break;
            self.dir = self.conf.right;
            break;
          case "ArrowDown":
            if (self.dir == self.conf.up) break;
            self.dir = self.conf.down;
            break;
          case "ArrowLeft":
            if (self.dir == self.conf.right) break;
            self.dir = self.conf.left;
            break;
        }
      },
      true
    );
  };

  p.rgCallBack = function (state, func, that, args) {
    var self = this;
    var cur = self.callList[state];
    if (!cur) {
      cur = [];
    }
    cur.push({
      func: func,
      self: that,
      args: args,
    });
    self.callList[state] = cur;
  };

  p.start = function () {
    var self = this;
    self.clear();
    self.initSnake();
    self.updateView();
    self.startTicker();
  };

  p.initDoc = function () {
    var self = this;
    var stageW = self.getStyle(self.container, "width");
    var w = self.docWidth + 2;
    //多少列
    var col = Math.floor(stageW / w);
    var row = Util.mathUp(self.docNum / col);

    for (let i = 0; i < self.docNum; i++) {
      var _row = Math.floor(i / col);
      var _col = i % col;

      self.createDoc(_row, _col);
      //不足一行补全
      if (_row == row - 1 && _col < col - 1 && i == self.docNum - 1) {
        for (let j = _col; j < col; j++) {
          _row = row - 1;
          _col = j % col;
          self.createDoc(_row, _col);
        }
      }
    }
    self.container.style.height = row * w + "px";
    self.container.style.width = col * w + "px";
    var div = document.createElement("div");
    div.style.clear = "both";
    div.style.width = "100%";
    self.container.appendChild(div);
  };

  p.createDoc = function (_row, _col) {
    var self = this;
    var w = self.docWidth + 2;
    var box = document.createElement("div");
    var key = _row + "_" + _col;
    box.className = "td";
    box.style.left = _col * w + "px";
    box.style.top = _row * w + "px";
    box.style.width = self.docWidth + "px";
    box.style.height = self.docWidth + "px";
    self.container.appendChild(box);
    self.docs[key] = box;
  };

  p.clear = function () {
    var self = this;
    self.clearTicker();
    self.clearView();
    self.roundRest();
  };

  p.getStyle = function (doc, attr) {
    return getComputedStyle(doc)[attr].replace("px", "");
  };

  p.startTicker = function () {
    var self = this;
    p.clearTicker();
    self.tickerId = setInterval(function () {
      self.update();
    }, self.US);
  };

  p.clearTicker = function () {
    if (this.tickerId) {
      clearInterval(this.tickerId);
    }
  };

  p.clearView = function () {
    var self = this;
    var keys = Object.keys(self.docs);
    keys.forEach(function (item) {
      self.docs[item].className = "td";
    });
  };

  p.roundRest = function () {
    var self = this;
    self.state = 0;
    self.snake = [];
    self.head = "";
    self.tail = "";
    self.point = [];
    self.pNum = 0;
  };

  /*游戏相关*/
  p.initSnake = function () {
    var self = this;
    self.dir = self.conf.right;
    self.pNum = 5;
    self.point = self.getPoint();
    self.snake = ["1_1", "1_2", "1_3", "1_4", "1_5"];
    self.tail = self.snake[0];
  };

  p.getPoint = function () {
    var self = this;
    var stageW = self.getStyle(self.container, "width");
    //多少列
    var col = Math.floor(stageW / (self.docWidth + 2));
    var row = Math.floor(self.docNum / col);
    var point = [];
    function random(c, r) {
      var rCol, rRow;
      rCol = Math.floor(c * Math.random());
      rRow = Math.floor(r * Math.random());
      return [rRow, rCol];
    }

    for (let i = 0; i < self.pNum; i++) {
      var key = "";
      do {
        key = random(col, row).join("_");
      } while (
        !self.docs[key] ||
        self.snake.indexOf(key) > -1 ||
        self.point.indexOf(key) > -1
      );

      point.push(key);
    }
    console.log(point);
    return point;
  };

  p.updateView = function () {
    var self = this;
    var tail = self.docs[self.tail];
    var dom;
    if (tail) {
      tail.className = "td";
    }
    self.point.forEach(function (key) {
      dom = self.docs[key];
      if (dom) {
        dom.className = "td black";
      }
    });
    self.snake.forEach(function (key, i, snake) {
      dom = self.docs[key];
      if (dom) {
        dom.className = i == snake.length - 1 ? "td red" : "td green";
      } else {
        self.gameOver();
      }
    });
  };

  p.go = function () {
    var self = this;
    var next;
    var dir = self.dir;
    var snake = self.snake;
    var head = snake[snake.length - 1];
    var aHead = head.split("_");
    switch (dir) {
      case self.conf.up:
        aHead[0]--;
        break;
      case self.conf.right:
        aHead[1]++;
        break;
      case self.conf.down:
        aHead[0]++;
        break;
      case self.conf.left:
        aHead[1]--;
        break;
    }
    next = aHead.join("_");

    if (self.snake.indexOf(next) > -1) {
      self.gameOver();
      return;
    }
    var pIdx = self.point.indexOf(next);
    if (pIdx > -1) {
      self.point.splice(pIdx, 1);
      if (self.point.length < 1) {
        self.point = self.getPoint();
      }
    } else {
      self.tail = self.snake.shift();
    }
    self.snake.push(next);
  };

  p.update = function () {
    var self = this;
    self.go();
    self.updateView();
  };
  p.gameOver = function () {
    var self = this;
    var cbs;
    console.log("得分: ", self.snake.length - 5);
    self.clear();
    self.doCallBack("gameOver");
  };

  p.doCallBack = function (key) {
    var self = this;
    var cbs = self.callList[key];
    if (cbs) {
      cbs.forEach(function (cbObj) {
        cbObj.func.apply(cbObj.self, cbObj.args);
      });
    }
  };

  return Game;
})();

var Util = (function () {
  function Util() {}

  Util.mathUp = function (num) {
    var int = Math.floor(num);
    if (num > int) {
      return int + 1;
    } else {
      return int;
    }
  };

  return Util;
})();
